<template>
  <div ref="canvas" />
</template>

<script lang="ts" setup>
import * as THREE from 'three';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { ref, onMounted } from "vue";

// 画布
const canvas = ref<any>('');
// 场景
const scene = new THREE.Scene();
// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1100);
camera.position.set(1, 0, 0);
camera.lookAt(0, 0, 0);
// 几何体
const geometry = new THREE.SphereGeometry(500, 100, 100);
// 反转x轴上的几何图形，使所有面都指向内侧
geometry.scale( - 1, 1, 1 );
// 纹理
const texture = new THREE.TextureLoader().load(new URL("@/assets/house.jpg", import.meta.url).href);
// 材质
const material = new THREE.MeshBasicMaterial({ map : texture });
// mesh
const mesh = new THREE.Mesh(geometry, material);
// 将 mesh 添加到 场景
scene.add(mesh);
// 渲染器
const renderer = new THREE.WebGLRenderer({ antialias : true });
renderer.setClearColor(0xffffff);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);


onMounted(() => {
  canvas.value.appendChild(renderer.domElement);
  // 当触控事件发生在元素上时，不进行任何操作
  canvas.value.style.touchAction = "none";
  // 指针按下
  canvas.value?.addEventListener( 'pointerdown', onPointerDown);
  // 鼠标滚轮
  document.addEventListener( 'wheel', onDocumentMouseWheel)
  // 窗口大小变化触发
  window.addEventListener( 'resize', onWindowResize);

  render();
});

/**
 * 窗口大小变化触发
 */
const onWindowResize = () => {
  // 更新相机长宽比
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机投影矩阵。在任何参数被改变以后必须被调用。
  camera.updateProjectionMatrix();
  // 更新渲染器大小
  renderer.setSize( window.innerWidth, window.innerHeight );
};

// 是否开启用户交互(手势操作)
let isUserInteracting = false;
// 鼠标指针按下的位置
let onPointerDownMouseX = 0, onPointerDownMouseY = 0;
//
let lon = 0, onPointerDownLon = 0;
let lat = 0, onPointerDownLat = 0;
let phi = 0, theta = 0;

/**
 * 指针按下
 * @param event
 */
function onPointerDown( event ) {

  if ( event.isPrimary === false ) return;

  isUserInteracting = true;

  onPointerDownMouseX = event.clientX;
  onPointerDownMouseY = event.clientY;

  onPointerDownLon = lon;
  onPointerDownLat = lat;

  document.addEventListener( 'pointermove', onPointerMove );
  document.addEventListener( 'pointerup', onPointerUp );

}

// 指针移动，计算经纬度
function onPointerMove( event ) {

  if ( event.isPrimary === false ) return;

  lon = ( onPointerDownMouseX - event.clientX ) * 0.1 + onPointerDownLon; // 经度
  lat = ( event.clientY - onPointerDownMouseY ) * 0.1 + onPointerDownLat; // 纬度

}

// 指针抬起，移除时间监听
function onPointerUp() {

  isUserInteracting = false;

  document.removeEventListener( 'pointermove', onPointerMove );
  document.removeEventListener( 'pointerup', onPointerUp );

}

// 鼠标滚轮， 控制FOV
function onDocumentMouseWheel( event ) {

  const fov = camera.fov + event.deltaY * 0.05;

  camera.fov = THREE.MathUtils.clamp( fov, 10, 75 );

  camera.updateProjectionMatrix();

}

// 动画
function render() {
  requestAnimationFrame( render );
  update();
}

function update() {
  // 用户未操作时开启VR自动迅游
  if ( isUserInteracting === false ) {
    // lon += 0.1;
  }

  lat = Math.max( - 85, Math.min( 85, lat ) ); // 纬度（这里的85是限制垂直视角）
  phi = THREE.MathUtils.degToRad( 90 - lat ); // 极角（垂直角度），从0到π（弧度）；degToRad 将度转化为弧度
  theta = THREE.MathUtils.degToRad( lon ); // 方位角（水平角度），从-π到π（弧度）

  // 根据极角和方位角计算出三维向量，500 是球的半径
  const x = 500 * Math.sin( phi ) * Math.cos( theta );
  const y = 500 * Math.cos( phi );
  const z = 500 * Math.sin( phi ) * Math.sin( theta );

  camera.lookAt( x, y, z );

  renderer.render( scene, camera );
}

</script>
